/*
 * Main Delegate
 *
 * Author: Kris Younger, NeXT Systems Engineering
 * You may freely copy, distribute and reuse the code in this example.  
 * NeXT disclaims any warranty of any kind, expressed or implied, as to 
 * its fitness for any particular use.
 */

#import "MainDelegate.h"
#import "GlobalThings.h"
#import "Transaction.h"
#import "LedgerController.h"

#import <ansi/time.h>
#import <objc/hashtable.h>

@implementation MainDelegate

- findAccount:sender
{
    char	*name;
    id		matrix;
    int		i;

    name = (char *)[editField stringValue];
    if ([self getAccountNamed:name] != nil) {
	matrix = [listBrowser matrixInColumn:0];
	for (i = [matrix cellCount]; i--;)
	    if (!strcmp(name, [[matrix cellAt:i :0] stringValue])) {
		[matrix selectCellAt:i :0];
		[self pickAccount:listBrowser];
		break;
	    }
    }

    return self;
}

- addAccount:sender
{
    id                  newRM, firstx;
    int                 h;
    const char         *aName;
    id                  accountStore;

    aName = [editField stringValue];
    if ([accountsStoreDirectory hasEntryNamed:aName] == NO) {
	[accountsStoreDirectory getBlock:&h andStore:&accountStore];
	[accountStore startTransaction];
	[accountsStoreDirectory addEntryNamed:aName ofClass:[IXRecordManager class]];
	newRM = [accountsStoreDirectory openEntryNamed:aName];
	[self addAllAttributes:newRM];
	[accountsHashTable insertKey:aName value:newRM];
	/* post an original transaction */
	firstx = [[Transaction alloc] init];
	[firstx setTMemo:"Initial Value."];
	[firstx setTAmount:0.0];
	h = [newRM addRecord:firstx];
	[accountStore commitTransaction];
    } else {
	NXRunAlertPanel("Alert", "An account by that name already exists.", "OK", NULL, NULL);
	return nil;
    }
    [self ping:self];
    return self;
}

- appDidInit:sender
{

    if ([self openDatabase]) {
    } else {
	[self initSchema];
	[self openDatabase];
    }

    [self makeListKey:self];
    return self;
}

- appWillTerminate:sender
{
    [self closeDatabase];
    return self;
}

- closeAccount:sender
{
    id                  ledger;

    [self findAccount:sender];
    if ((currentAccount != NULL) && (currentAccount != nil)) {
	if ([ledgersHashTable isKey:currentAccountName] == YES) {
	    ledger = [ledgersHashTable valueForKey:currentAccountName];
	    [ledgersHashTable removeKey:currentAccountName];
	    [(LedgerController *) ledger closeAccount:self];
	    [(LedgerController *) ledger free];
	};
    };
    return self;
}

- doubleClickAccount:sender
{
    [self pickAccount:sender];
    [self openAccount:sender];
    return self;
}

- makeListKey:sender
{
    [listBrowser loadColumnZero];
    [listBrowser setDoubleAction:@selector(doubleClickAccount:)];
    [listWindow makeKeyAndOrderFront:self];
    [editField selectText:self];
    return self;
}

- openAccount:sender
{
    id                  newAccount;

    [self findAccount:sender];
    if ((currentAccount != NULL) && (currentAccount != nil)) {
	if ([ledgersHashTable isKey:currentAccountName] == YES) {
	    [(id)[ledgersHashTable valueForKey:currentAccountName] makeKey:self];
	} else {
	    newAccount = [[LedgerController alloc] initWith:currentAccount
			  named:currentAccountName];
	    [ledgersHashTable insertKey:currentAccountName value:newAccount];
	    [newAccount makeKey:self];
	};
    }
    return self;
}

- ping:sender
{
    [self makeListKey:sender];
    return self;
}

- pickAccount:sender
{
    BOOL                isSelected;

    isSelected = NO;
    currentAccount = [self getAccountNamed:[[[sender matrixInColumn:0] selectedCell] stringValue]];
    if ((currentAccount != NULL) && (currentAccount != nil)) {
	isSelected = YES;
	currentAccountName = [[[sender matrixInColumn:0] selectedCell] stringValue];
	currentAccountName = NXUniqueString(currentAccountName);
    }

    if (isSelected == YES) {
	[openButton setEnabled:YES];
	[closeButton setEnabled:YES];
	[editField setStringValue:currentAccountName];
	[removeButton setEnabled:YES];
    } else {
	[addButton setEnabled:NO];
	[removeButton setEnabled:NO];
	[openButton setEnabled:NO];
	[closeButton setEnabled:NO];
    }
    return self;
}

- removeAccount:sender
{
    id                  account;
    id			accountStore;
    unsigned		block;

    [self closeAccount:self];
    if ((currentAccount != NULL) && (currentAccount != nil)) {
	if ((account = [self getAccountNamed:currentAccountName]) != nil) {
	    [accountsStoreDirectory getBlock:&block andStore:&accountStore];
	    [accountStore startTransaction];
	    [accountsStoreDirectory removeName:currentAccountName];
	    [accountsHashTable removeKey:currentAccountName];
	    [account freeFromStore];
	    [accountStore commitTransaction];
	};
    };
    [self ping:self];
    return self;
}

- (const char *)todaysDate
{
    char                buffer[32];
    struct tm          *timeptr;
    time_t              timer;

    time(&timer);
    timeptr = localtime(&timer);
    strftime(buffer, sizeof(buffer), "%m/%d/%y", timeptr);
    return NXUniqueString(buffer);
}

- (int)consumeSerial
{
    return [globalThings consumeSerial];
}

- (int)browser:b fillMatrix:m inColumn:(int)c
{
    int                 cnt;
    int                 i;
    id                  t;

    if (list)
	free(list);
    list = [self listOfAccountNames];
    i = cnt = 0;
    if (list != NULL)
	while (list[i]) {
	    [m addRow];
	    t = [m cellAt:i :0];
	    [t setStringValue:list[i]];
	    [t setLoaded:YES];
	    [t setLeaf:YES];
	    cnt += 1;
	    i += 1;
	};

    return cnt;
}

- initSchema
{
    id                  tmpSC;
    int                 handle;

 /* create main Archive */
    NXRunAlertPanel("Welcome.", "Creating Ledger.store.", "OK", NULL, NULL);
    mainStoreDirectory = [[IXStoreDirectory alloc] 
	initWithName:"Archive" inFile:"Ledger.store"];
    [mainStoreDirectory getBlock:&handle andStore:&mainStoreHandle];
    if ([mainStoreDirectory hasEntryNamed:"Accounts"] == NO) {
	accountsStoreDirectory = [mainStoreDirectory 
	    addEntryNamed:"Accounts" ofClass:[IXStoreDirectory class]];
    }
    if ([mainStoreDirectory hasEntryNamed:"Globals"] == NO) {
	tmpSC = [mainStoreDirectory addEntryNamed:"Globals" ofClass:[IXRecordManager class]];
	[tmpSC addAttributeNamed:"Globals" forSelector:@selector(identification)];
	globalThings = (GlobalThings *)[[GlobalThings alloc] init];
	[tmpSC addRecord:globalThings];
    }
 /* the following two lines enable transactions in the storeFile. */
    [mainStoreHandle startTransaction];
    [mainStoreHandle commitTransaction];
    [mainStoreDirectory free];
    return self;
}

- openDatabase
{
    int                 handle;
    id                  cursor;

    if (mainStoreDirectory = [[IXStoreDirectory alloc] initFromName:"Archive"
			      inFile:"Ledger.store" forWriting:YES]) {
	[mainStoreDirectory getBlock:&handle andStore:&mainStoreHandle];
	[mainStoreHandle startTransaction];
	[mainStoreHandle commitTransaction];
	if ([mainStoreDirectory hasEntryNamed:"Accounts"] == YES) {
	    accountsStoreDirectory = [mainStoreDirectory openEntryNamed:"Accounts"];
	}
	if ([mainStoreDirectory hasEntryNamed:"Globals"] == YES) {
	    globalThingsRecordManager = [mainStoreDirectory openEntryNamed:"Globals"];
	}
	cursor = [globalThingsRecordManager cursorForAttributeNamed:"Globals"];
	if ([cursor setKey:(void *)GLOBALVARIDENT
	     andLength:(strlen(GLOBALVARIDENT) + 1)] == YES) {
	    handle = [cursor setFirstHandle];
	    globalThings = [globalThingsRecordManager readRecord:handle fromZone:[self zone]];
	}
	[cursor free];
	accountsHashTable = [[HashTable alloc] initKeyDesc:"*"];
	ledgersHashTable = [[HashTable alloc] initKeyDesc:"*"];
    }
    if (mainStoreDirectory == nil)
	return nil;
    return self;
}

- closeDatabase
{
    [mainStoreHandle startTransaction];
    [globalThingsRecordManager replaceRecord:[globalThings handle] with:globalThings];
    [mainStoreHandle commitTransaction];
    [mainStoreDirectory free];
    return self;
}

- (char **)listOfAccountNames
{
    return [accountsStoreDirectory entries];
}

- getAccountNamed:(const char *)aName
{
    id                  account = nil;

    if ([accountsStoreDirectory hasEntryNamed:aName] == YES) {
	aName = NXUniqueString(aName);
	if ((account = [accountsHashTable valueForKey:aName]) == nil) {
	    if ((account = [accountsStoreDirectory openEntryNamed:aName]) != nil)
		[accountsHashTable insertKey:aName value:account];
	};
    };
    return account;
}

- (BOOL)textWillChange:textObject
{
    [addButton setEnabled:YES];
    return NO;
}

- (BOOL)textWillEnd:textObject
{
    [self findAccount:listBrowser];
    [self openAccount:listBrowser];
    return NO;
}

- textDidChange:textObject
{
    currentAccount = nil;
    currentAccountName = NULL;
    return self;
}

- addAllAttributes:aRecMgr
{
    [mainStoreHandle startTransaction];
    [aRecMgr addAttributeNamed:"tSerial" forSelector:@selector(tSerial)];
    [aRecMgr addAttributeNamed:"tNumber" forSelector:@selector(tNumber)];
    [aRecMgr addAttributeNamed:"tDate" forSelector:@selector(tDate)];
    [aRecMgr addAttributeNamed:"tMemo" forSelector:@selector(tMemo)];
    [aRecMgr addAttributeNamed:"tDebit" forSelector:@selector(tDebit)];
    [aRecMgr addAttributeNamed:"tCredit" forSelector:@selector(tCredit)];
    [mainStoreHandle commitTransaction];
    return self;
}


@end
